package com.ming.common.dynamic;

import cn.hutool.core.thread.ThreadUtil;
import com.ming.common.dynamic.code.IClassExecuter;
import com.ming.common.dynamic.code.IStringCompiler;
import com.ming.common.dynamic.code.RunSourceHandler;
import com.ming.common.dynamic.code.config.RunSourceProperties;
import com.ming.common.dynamic.code.core.ClassExecuter;
import com.ming.common.dynamic.code.core.JaninoCompiler;
import com.ming.common.dynamic.code.dto.ClassBean;
import com.ming.common.dynamic.code.dto.ExecuteResult;
import com.ming.common.dynamic.code.dto.Parameters;
import com.ming.common.init.LogInit;
import com.ming.common.liteflow.vo.IvyDynamicClassVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class IvyClassHelper {

    private static final Logger LOG = LoggerFactory.getLogger(IvyClassHelper.class);

    public static ClassBean load(String sourceCode) throws Exception {
        Map<String, String> hackers = new HashMap<>();
        RunSourceProperties calTime = new RunSourceProperties();
        calTime.setCalCompileTime(true);
        IStringCompiler compiler = new JaninoCompiler();
        IClassExecuter<ExecuteResult> executer = new ClassExecuter();
        RunSourceHandler handler = new RunSourceHandler(compiler, executer, calTime, hackers);
        return handler.loadClassFromSource(sourceCode);
    }

    public static List<ClassBean> load(List<String> sourceCodeList) throws Exception {
        Map<String, String> hackers = new HashMap<>();
        RunSourceProperties calTime = new RunSourceProperties();
        calTime.setCalCompileTime(true);
        IStringCompiler compiler = new JaninoCompiler();
        IClassExecuter<ExecuteResult> executer = new ClassExecuter();
        RunSourceHandler handler = new RunSourceHandler(compiler, executer, calTime, hackers);
        return handler.loadClassFromSource(sourceCodeList);
    }

    public static Map<String,Object> run(IvyDynamicClassVo vo) throws Exception {
        return run(vo.getPackagePath(), vo.getSourceCode(), vo.getMethodName(), vo.getParams());
    }

    public static Map<String,Object> run(String packagePath, String sourceCode, String methodName, Object[] params) throws Exception {
        Map<String, String> hackers = new HashMap<>();
        RunSourceProperties calTime = new RunSourceProperties();
        calTime.setCalCompileTime(true);
        IStringCompiler compiler = new JaninoCompiler();
        IClassExecuter<ExecuteResult> executer = new ClassExecuter();
        RunSourceHandler handler = new RunSourceHandler(compiler, executer, calTime, hackers);

        long ms = System.currentTimeMillis();
        String startKey = ms + LogInit.startKey;
        String endKey = ms + LogInit.endKey;

        LOG.info(startKey);
        ExecuteResult result = null;
        try {
            Parameters pars = new Parameters();
            if(params != null){
                for (int i=0;i<params.length;i++){
                    pars.add(params[i]);
                }
            }
            if(!sourceCode.startsWith("package")){
                packagePath = "package "+packagePath+";";
            }else{
                packagePath = "";
            }
            // 重新编译加载源码类
            result = handler.runMethod(packagePath + sourceCode, methodName, pars, false, true);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println(e.getMessage());
            StackTraceElement[] stackTrace = e.getStackTrace();
            List<String> list = new ArrayList<>();
            for (StackTraceElement element : stackTrace){
                list.add(element.toString());
            }
            System.out.println(String.join(System.lineSeparator(),list));
        }
        LOG.info(endKey);

        List<String> list = LogInit.logMap.get(endKey);
        while (list == null || list.isEmpty()) {
            list = LogInit.logMap.get(endKey);// 等待list不为空
            ThreadUtil.sleep(100);
        }
        LogInit.logMap.remove(endKey);
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("returnVal", result != null ? String.valueOf(result.getReturnVal()) : "null");
        resultMap.put("logStr", String.join(System.lineSeparator(),list));
        return resultMap;
    }

}
